package com.zpig333.runesofwizardry.api;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.registry.GameRegistry;
import com.zpig333.runesofwizardry.RunesOfWizardry;
import com.zpig333.runesofwizardry.block.ADustStorageBlock;
import com.zpig333.runesofwizardry.core.References;
import com.zpig333.runesofwizardry.core.WizardryRegistry;
import com.zpig333.runesofwizardry.core.rune.RunesUtil;
import com.zpig333.runesofwizardry.core.rune.RunesUtil.InvalidRuneException;
import com.zpig333.runesofwizardry.item.ItemInscription;
import com.zpig333.runesofwizardry.item.dust.DustPlaceholder;
import com.zpig333.runesofwizardry.runes.inscription.RuneInscription;
import com.zpig333.runesofwizardry.util.Utils;
/** Dust API registry. All dust registry methods are found here. */
public class DustRegistry {
/** List of all registered dusts **/
private static List<IDust> dusts = new LinkedList<IDust>();
private static List<DustPlaceholder> placeholders = new LinkedList<DustPlaceholder>();
/** map of all the storage blocks**/
private static Map<IDust,IDustStorageBlock> blocks = new HashMap<IDust,IDustStorageBlock>();
/** Map of all the infusion recipes **/
//FUTURE use a custom IRecipe or something
//private static Map<ItemStack[], ItemStack> recipes = new HashMap<ItemStack[], ItemStack>();
/**List of all registered runes**/
private static Map<String,IRune> runes = new LinkedHashMap<String, IRune>();
//this is less safe than the BiMap thing, but will stay in registration order
private static Map<IRune,String> inverseRunes = new LinkedHashMap<IRune, String>();
/** The dust requirements for all runes**/
private static Map<String,RunesUtil.RuneStats> duststats = new HashMap<String, RunesUtil.RuneStats>();
/**List of all registered inscriptions**/
private static Map<String,Inscription> inscriptions=new LinkedHashMap<String, Inscription>();
//reverse inscription map
private static Map<Inscription,String> inverseInscriptions = new LinkedHashMap<Inscription, String>();
//Special constants
/**
* Represents any "magic" dust
*/
public static final IDust MAGIC_DUST = new DustPlaceholder("magic", 0xff00e0, true){
/* (non-Javadoc)
* @see com.zpig333.runesofwizardry.api.IDust#dustsMatch(net.minecraft.item.ItemStack, net.minecraft.item.ItemStack)
*/
@Override
public boolean dustsMatch(ItemStack thisDust, ItemStack other) {
IDust otherDust = getDustFromItemStack(other);
return otherDust.isMagicDust(other) && !(otherDust instanceof DustPlaceholder);
}
};
/** represents any dust **/
public static final IDust ANY_DUST = new DustPlaceholder("any", 0x00ffff, false){
/* (non-Javadoc)
* @see com.zpig333.runesofwizardry.api.IDust#dustsMatch(net.minecraft.item.ItemStack, net.minecraft.item.ItemStack)
*/
@Override
public boolean dustsMatch(ItemStack thisDust, ItemStack other) {
IDust oDust = getDustFromItemStack(other);
return !(oDust instanceof DustPlaceholder);
}
};
/** returns a list of all the registered dusts.
*
* @return a LinkedList of all the dusts, in the order they were registered
*/
public static List<IDust> getAllDusts(){
return new LinkedList<IDust>(dusts);
}
/**
* returns all registered placeholder dusts
* @return a LinkedList of the placeholder dusts, in the order of registration
*/
public static List<DustPlaceholder> getPlaceholders(){
return new LinkedList<DustPlaceholder>(placeholders);
}
/** returns all the registered runes
*
* @return a LinkedList of all runes, in the order they were registered
*/
public static List<IRune> getAllRunes(){
return new LinkedList<IRune>(runes.values());
}
/**
* Returns the rune registered as the given id, or null if the ID is not found
* @param id the id to get the rune for
* @return the rune registered as {@code id}, or {@code null} if it dosen't exist
*/
@Nullable
public static IRune getRuneByID(String id){
return runes.get(id);
}
/**
* Returns the full ID of a rune (modid:runeid)
* @param rune the rune for which to look up the ID
* @return the id for the rune, in the form modid:runeid
*/
public static String getRuneID(IRune rune){
//inverse is stored in the bimap, so calling it all the time shouldn't be a performance issue
return inverseRunes.get(rune);
}
/**
* Returns all registered rune IDs
* @return a set of the registered rune IDs (modid:runeID)
*/
public static Set<String> getRuneIDs(){
return runes.keySet();
}
/**
* Returns size and cost stats for the rune, including a list of the dusts required to build a rune. /!\ Do NOT edit this list or any of the ItemStacks in it, things WILL break
* @param id the identifier of the rune for which to get the cost
* @return the dusts required to build the rune identified by id, as well as its size and centering
*/
public static RunesUtil.RuneStats getRuneStats(String id){
return duststats.get(id);
}
/** Given a dust, returns the block that was created in registerDust
*
* @param dust the dust to find the block for
* @return the block created from this dust, or {@code null} if it has a custom block
*/
public static IDustStorageBlock getBlock(IDust dust){
return blocks.get(dust);
}
public static Collection<IDustStorageBlock> getAllBlocks(){
return blocks.values();
}
@Nullable
public static Inscription getInscriptionByID(String id){
return inscriptions.get(id);
}
@Nullable
public static String getInscriptionID(Inscription ins){
return inverseInscriptions.get(ins);
}
public static Set<String> getInscIDs(){
return inscriptions.keySet();
}
public static ItemStack getStackForInscription(String inscriptionID){
ItemStack stack = new ItemStack(WizardryRegistry.inscription,1,1);
stack.getOrCreateSubCompound(References.modid).setString(Inscription.NBT_ID, inscriptionID);
return stack;
}
@Nullable
public static Inscription getInscriptionFromStack(ItemStack stack){
if(!stack.isEmpty() && stack.getItem()==WizardryRegistry.inscription){
NBTTagCompound tag = stack.getSubCompound(References.modid);
if(tag!=null){
String id = tag.getString(Inscription.NBT_ID);
return getInscriptionByID(id);
}
}
return null;
}
/**
* Returns the inscription worn by a player
* @param player
* @return ItemStack.EMPTY if no inscription is worn or if more than one inscription is worn and double inscriptions are disabled
*/
@Nonnull
public static ItemStack getWornInscription(EntityPlayer player){
return ((ItemInscription)WizardryRegistry.inscription).getWornInscription(player);
}
/**
* Registers a valid dust into the RunesOfWizardry system. MUST EXTEND IDUST!!
* <br/>Note: also registers it as an Item in the GameRegistry, sets up its unlocalized name and creative tab.
*/
public static void registerDust(final IDust dustclass) {
//add it to our list of dusts
dusts.add(dustclass);
if(dustclass instanceof DustPlaceholder){
placeholders.add((DustPlaceholder) dustclass);
}
String modID = Utils.getCurrentModID();
dustclass.setUnlocalizedName(modID+"_"+dustclass.getName());
dustclass.setCreativeTab(dustclass.creativeTab());
//list of subItems
int[] metavalues = dustclass.getMetaValues();
//if we have meta-based subdusts, mark it as such
if(metavalues.length>1){
dustclass.setHasSubtypes(true);
}
//register the dust item with the appropriate modid
GameRegistry.register(dustclass, new ResourceLocation(modID,dustclass.getName()));
RunesOfWizardry.proxy.registerDustItemRender(dustclass);
//create the block form of the dust
IDustStorageBlock dustBlock;
if(!dustclass.hasCustomBlock()){
dustBlock = new ADustStorageBlock(Material.SAND,modID) {
@Override
public IDust getIDust() {
return dustclass;
}
};
RunesOfWizardry.proxy.registerDustBlockRender((ADustStorageBlock)dustBlock);
}else {
dustBlock = dustclass.getCustomBlock();
}
if(dustBlock!=null){
blocks.put(dustclass, dustBlock);
//Crafting the blocks
for(int i:metavalues){
ItemStack dust = new ItemStack(dustclass,1,i);
GameRegistry.addShapedRecipe(new ItemStack(dustBlock.getInstance(), 1, i),
new Object[]{"XXX","XXX","XXX",'X',dust});
GameRegistry.addShapelessRecipe(new ItemStack(dustclass,9,i), new ItemStack(dustBlock.getInstance(), 1, i));
}
}
}
/** Validates and registers a rune in the RunesOfWizardry system.
*
* @param rune the rune to register
* @param the mod-unique ID for the rune (will be prefixed with your modid)
* @throws InvalidRuneException if the given rune is invalid
*/
public static void registerRune(final IRune rune,String id){
RunesUtil.RuneStats stats = RunesUtil.validateRune(rune);
String modID = Utils.getCurrentModID();
String name=modID+":"+id;
//maybe do crash report (or skip registration)
if(runes.containsKey(name))throw new IllegalArgumentException("A rune with the id: "+name+" Already exists!");
runes.put(name,rune);
inverseRunes.put(rune, name);
duststats.put(name, stats);
}
/** Validates and registers an inscription in the RunesOfWizardry system.
*
* @param inscription the inscription to register
* @param id the mod-unique ID for the inscription (will be prefixed with your modid)
* @throws InvalidInscriptionException if the given inscription is invalid
*/
public static void registerInscription(final Inscription inscription,String id){
String modID = Utils.getCurrentModID();
String name=modID+":"+id;
//maybe do crash report (or skip registration)
if(inscriptions.containsKey(name))throw new IllegalArgumentException("An Inscription with the id: "+name+" Already exists!");
registerRune(new RuneInscription(inscription), name+"_inscription");
inscriptions.put(name,inscription);
inverseInscriptions.put(inscription, name);
}
/**
*
* @param materials the recipe to infuse the dust
* @param blockIn the block/item to be infused (usually a block of inert dust)
* @param blockOut the result (usually a block of your dust)
*/
public static void registerBlockInfusion(ItemStack[] materials, ItemStack blockIn, ItemStack blockOut){
//FUTURE temporary until we figure out what we want
ItemStack[] recipe = new ItemStack[materials.length+1];
for(int i=0;i<materials.length;i++){
recipe[i]=materials[i];
}
recipe[materials.length]=blockIn;
GameRegistry.addShapelessRecipe(blockOut, (Object[])recipe);
}
/** Returns the dust class from an ItemStack
* @return the IDust in the ItemStack
* @throws IllegalArgumentException if the ItemStack is not a dust
*/
public static IDust getDustFromItemStack(ItemStack stack){
Item item = stack.getItem();
if(item instanceof IDust){
return (IDust)item;
}else{
throw new IllegalArgumentException("The Item is not a dust");
}
}
/** Find if a given Block is placed Dust
* @param blockState the block to check
* @return {@code true} if the argument is placed dust
**/
public static boolean isDust(IBlockState blockState){
if(blockState.getBlock() == WizardryRegistry.dust_placed){
return true;
}
else{
return false;
}
}
}